/*
 * Copyright (c) 2020 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "moyq5.h"
#include "m_socket.h"
#include "m_cmd_decode.h"
#include "m_cmd_handle.h"
#include "m_log.h"
#include "m_utils.h"
#include "m_nrf2401.h"

#include <stdio.h>
#include <unistd.h>

#include "lwip/netif.h"
#include "lwip/netifapi.h"
#include "lwip/dhcp.h"
#include "lwip/ip4_addr.h"

#include "cmsis_os2.h"
#include "ohos_init.h"
#include "ohos_types.h"
#include "iot_gpio.h"
#include "wifi_hotspot.h"

#include "wifi_device.h"
#include "wifi_error_code.h"

#define LED_TEST_GPIO 9 // for hispark_pegasus
#define LED_INTERVAL_TIME_US 300000

const char *g_ssid = "SSD";
const char *g_preSharedKey = "sanstar2017";
WifiEvent g_staEventHandler = {0};
struct netif *g_staNetif = NULL;
static int g_hasAddr = 0;
static int g_hasConnected = 0;
static unsigned int g_serverPort = 8080;
static char *g_serverAddr = "192.168.0.227";

static decode_cache g_cache = {0};



static void NetifStatusCallback(struct netif *netif)
{
    m_log_d(M_MOYQ5_H, "Go IP\n");
    char *ip_str = NULL;
    char *mask_str = NULL;
    char *gw_str = NULL;

    ip4_addr_t ip;
    ip4_addr_t mask;
    ip4_addr_t gw;
    netifapi_netif_get_addr(netif, &ip, &mask, &gw);

    ip_str = ip4addr_ntoa(&ip);
    m_log_d(M_MOYQ5_H, "ip: %s", ip_str);
    mask_str = ip4addr_ntoa(&mask);
    m_log_d(M_MOYQ5_H, "mask: %s", mask_str);
    gw_str = ip4addr_ntoa(&gw);
    m_log_d(M_MOYQ5_H, "gw: %s", gw_str);

}
static void StaResetAddr(struct netif *ptrLwipNetif)
{
    ip4_addr_t staGW;
    ip4_addr_t staIpaddr;
    ip4_addr_t staNetmask;

    if (ptrLwipNetif == NULL) {
        m_log_e(M_MOYQ5_H, "[sample] Null param of netdev\r\n");
        return;
    }

    IP4_ADDR(&staGW, 0, 0, 0, 0);
    IP4_ADDR(&staIpaddr, 0, 0, 0, 0);
    IP4_ADDR(&staNetmask, 0, 0, 0, 0);

    netifapi_netif_set_addr(ptrLwipNetif, &staIpaddr, &staNetmask, &staGW);
}

static void WifiConnectionChangedHandler(int state, WifiLinkedInfo *info)
{
    m_log_d(M_MOYQ5_H, "OnWifiConnectionChanged: state=%d,wifiLinkedInfo[ssid=%s,bssid=%s,rssi=%d,band=%d,frequency=%d,connState=%d, ipAddress=%d]\n",
    state,info->ssid,info->bssid,info->rssi,info->band,info->frequency,info->connState,info->ipAddress);
    if (state == WIFI_STATE_AVALIABLE) {
        netifapi_dhcp_start(g_staNetif);
    } else if (state == WIFI_STATE_NOT_AVALIABLE) {
        netifapi_dhcp_stop(g_staNetif);
        StaResetAddr(g_staNetif);
    }
}
static void WifiScanStateChangedHandler(int state, int size)
{
    m_log_d(M_MOYQ5_H, "OnWifiScanStateChanged: state=%d,size=%d\n", state,size);
}
static void HotspotStateChangedHandler(int state)
{
    m_log_d(M_MOYQ5_H, "OnHotspotStateChanged: state=%d\n", state);
}
static void HotspotStaJoinHandler(StationInfo *info)
{
    m_log_d(M_MOYQ5_H, "OnHotspotStaJoin: stationInfo[name=%s,macAddress=%s,ipAddress=%d,disconnectedReason=%d]\n",
    info->name,info->macAddress,info->ipAddress,info->disconnectedReason);
}
static void HotspotStaLeaveHandler(StationInfo *info)
{
    m_log_d(M_MOYQ5_H, "OnHotspotStaJoin: stationInfo[name=%s,macAddress=%s,ipAddress=%d,disconnectedReason=%d]\n",
    info->name,info->macAddress,info->ipAddress,info->disconnectedReason);
}
static int SocketReceiveDataHandler(const char *buf, unsigned int size)
{
    #ifdef M_LOG_TRACE
    unsigned char hex[size * 2];
    m_to_hex(buf, size, hex);
    m_log_t(M_MOYQ5_H, "dill with data: %s\n", hex);
    #endif

    //struct CmdInfo *infos[50];
    int r;

    char *buf_;
    buf_ = (char *) malloc(size * sizeof(char));
    memcpy(buf_, buf, size * sizeof(char));

    decode_data data = {buf_, size, 0};

    decode_result result = {0};
    result.buf = (char *) malloc(PK_MAX * sizeof(char));

    do {
        r = m_decode(&g_cache, &data, &result);
        if (r == 2) {// 终止
            break;
        }
        if (r == 0) {// 解码成功
            m_cmd_handle(&result);
        }
        // else r == 1 包结构有误，根据index 决定是否需要继续解码剩下内容
    } while(data.index > 0);

    free(data.buf);
    free(result.buf);
    return r;
}
static void PrintfAddr()
{
    int ret;
    struct netif *netif_node = netif_find("wlan0");
    if (netif_node == NULL) {
        m_log_e(M_MOYQ5_H, "GetLocalWifiIp netif get fail\n");
        return;
    }

    ip4_addr_t ipAddr;
    ip4_addr_t netMask;
    ip4_addr_t gateWay;

    ret = netifapi_netif_get_addr(netif_node, &ipAddr, &netMask, &gateWay);
    if (ret == 0) {
        if (g_hasAddr == 0 && ipAddr.addr != 0) {
            g_hasAddr = 1;
            //g_serverAddr = ip4addr_ntoa(&ipAddr);
        }
        m_log_t(M_MOYQ5_H, "IP: %s\n", ip4addr_ntoa(&ipAddr));
        m_log_t(M_MOYQ5_H, "MASK: %s\n", ip4addr_ntoa(&netMask));
        m_log_t(M_MOYQ5_H, "GATEWAY: %s\n", ip4addr_ntoa(&gateWay));
        return;
    }
    m_log_e(M_MOYQ5_H, "get ip fail\n");
    return;
}
void HelloMoyq5(void)
{

    m_nrf_init();

    WifiDeviceConfig devCfg;
    int netId;
    int r;
    struct dhcp *dhcp;

    memset_s(&g_staEventHandler, sizeof(WifiEvent), 0, sizeof(WifiEvent));
    g_staEventHandler.OnWifiConnectionChanged = WifiConnectionChangedHandler;
    g_staEventHandler.OnWifiScanStateChanged = WifiScanStateChangedHandler;
    g_staEventHandler.OnHotspotStateChanged = HotspotStateChangedHandler;
    g_staEventHandler.OnHotspotStaJoin = HotspotStaJoinHandler;
    g_staEventHandler.OnHotspotStaLeave = HotspotStaLeaveHandler;
    r = RegisterWifiEvent(&g_staEventHandler);
    if (r != WIFI_SUCCESS) {
        m_log_e(M_MOYQ5_H, "register wifi event fail: %d\n", r);
        return;
    }

    r = EnableWifi();
    if (r != WIFI_SUCCESS) {
        m_log_e(M_MOYQ5_H, "enable wifi fail: %d\n", r);
        return;
    }
    m_log_d(M_MOYQ5_H, "wifi enable success\n");

    memset_s(&devCfg, sizeof(WifiDeviceConfig), 0, sizeof(WifiDeviceConfig));
    strncpy_s(devCfg.ssid, sizeof(devCfg.ssid), g_ssid, strlen(g_ssid));
    strncpy_s(devCfg.preSharedKey, sizeof(devCfg.preSharedKey), g_preSharedKey, strlen(g_preSharedKey));

    devCfg.securityType = WIFI_SEC_TYPE_PSK;//WIFI_SEC_TYPE_OPEN;//WIFI_SEC_TYPE_PSK;
    devCfg.ipType = DHCP;

    r = AddDeviceConfig(&devCfg, &netId);
    if (r != WIFI_SUCCESS) {
        m_log_e(M_MOYQ5_H, "wifi add config fail: %d\n", r);
        return;
    }
    m_log_d(M_MOYQ5_H, "wifi add config success\n");

    r = ConnectTo(netId);
    if (r != WIFI_SUCCESS) {
        m_log_e(M_MOYQ5_H, "wifi connect fail: %d\n", r);
        return;
    }
    m_log_d(M_MOYQ5_H, "wifi connect success\n");

    //g_staNetif = netif_find("wlan0");
    //if (g_staNetif == NULL) {
    //    printf("[sample] Get netif failed\n");
    //    return;
    //}
    //g_staNetif->status_callback = NetifStatusCallback;
    //netifapi_dhcp_set_struct(g_staNetif, dhcp);
    //netifapi_dhcp_start(g_staNetif);

    struct ReceiveDataListener listener = {0};
    //memset_s(&listener, sizeof(ReceiveDataListener), 0, sizeof(ReceiveDataListener));
    listener.onReceive = SocketReceiveDataHandler;

    WifiLinkedInfo info = {0};
    memset_s(&info, sizeof(WifiLinkedInfo), 0, sizeof(WifiLinkedInfo));
    while(1) {
        r = GetLinkedInfo(&info);
        if (r != WIFI_SUCCESS) {
            m_log_e(M_MOYQ5_H, "wifi get linked info fail: %d\n", r);
        } else {
            //printf("linked info: ssid=%s,bssid=%s,rssi=%d,band=%d,frequency=%d,connState=%d, ipAddress=%d\n",
            //info.ssid,info.bssid,info.rssi,info.band,info.frequency,info.connState,info.ipAddress);
        }
        PrintfAddr();
        if (g_hasAddr && !g_hasConnected) {
            r = m_connect(g_serverPort, g_serverAddr);
            if (r == 0) {
                g_hasConnected = 1;
                m_startReceiveData(&listener);
            }
        }
        usleep(1000000);
    }
    return;

    HotspotConfig config;
    m_log_d(M_MOYQ5_H, "hello moyq5!\n");

    int ret = GetHotspotConfig(&config);
    if (ret != WIFI_SUCCESS) {
        m_log_e(M_MOYQ5_H, "get wifi hotspot config fail\n");
    }
    config.ssid[5] = "moyq5";
    config.securityType = WIFI_SEC_TYPE_PSK;
    config.band = HOTSPOT_BAND_TYPE_5G;
    config.channelNum = 1;
    config.preSharedKey[6] = "123456";

    ret = SetHotspotConfig(&config);
    if (ret != WIFI_SUCCESS) {
        m_log_e(M_MOYQ5_H, "set wifi hotspot config fail\n");
    }
    ret = EnableHotspot();
    if (ret != WIFI_SUCCESS) {
        m_log_e(M_MOYQ5_H, "enable wifi hotspot fail\n");
    }
    IoTGpioInit(LED_TEST_GPIO);
    IoTGpioSetDir(LED_TEST_GPIO, IOT_GPIO_DIR_OUT);
    while(1) {
        m_log_d(M_MOYQ5_H, "关灯\n");
        IoTGpioSetOutputVal(LED_TEST_GPIO, 0);
        usleep(LED_INTERVAL_TIME_US);
        m_log_d(M_MOYQ5_H, "开灯\n");
        IoTGpioSetOutputVal(LED_TEST_GPIO, 1);
        usleep(LED_INTERVAL_TIME_US);
    }
}

SYS_RUN(HelloMoyq5);
